//
//  a.swift
//  boleh
//
//  Created by BO ZHOU on 2020/9/8.
//  Copyright © 2020 BO ZHOU. All rights reserved.
//

import UIKit

open class RectRadarAnimationView: UIView {
    
    fileprivate static let Tag: Int = 0xAAAAAA
    
    private var reusableRadarCells: [RadarCell] = []
    
    private var isAnimation: Bool = false
    
    private var maxIncrement: CGFloat
    
    private var fillColor: UIColor
    
    private var beginAlpha: CGFloat
    
    private let addScheduleKey = "com.putao.bloks.radar.add.schedule.key-\(Int.random(in: 0...9999999))"
    private let animateScheduleKey = "com.putao.bloks.radar.animate.schedule.key-\(Int.random(in: 0...9999999))"
    
    required public init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    init(beginFrame frame: CGRect,  expand increment: CGFloat, fillColor: UIColor, beginAlpha: CGFloat) {
        self.maxIncrement = increment
        self.fillColor = fillColor
        self.beginAlpha = beginAlpha
        super.init(frame: frame.inset(by: UIEdgeInsets(top: -increment, left: -increment, bottom: -increment, right: -increment)))
    }
    
    public override func removeFromSuperview() {
        RadarScheduler.manager.remove(for: addScheduleKey)
        AnimateScheduler.manager.remove(for: animateScheduleKey)
        super.removeFromSuperview()
    }
    
    func addAnimation() {
        RadarScheduler.manager.add(target: self, identifier: addScheduleKey) { [weak self] in
            self?.addRadarCell()
        }
        AnimateScheduler.manager.add(target: self, identifier: animateScheduleKey) { [weak self] in
            self?.radarAnimation()
        }
    }
    
    func addRadarCell() {
        let radarCell: RadarCell = { [weak self] in
            if let cell = self?.reusableRadarCells.safeRemoveFirst() {
                cell.progress = 0.0
                return cell
            }
            return RadarCell(beginFrame: bounds.inset(by: UIEdgeInsets(maxIncrement)), expand: maxIncrement, fillColor: fillColor, beginAlpha: beginAlpha)
        }()
        addSubview(radarCell)
    }
    
    func radarAnimation() {
        subviews.forEach {
            guard let radarView = $0 as? RadarCell else {
                return
            }
            radarView.progress += 0.006
            if radarView.progress >= 1.0 {
                radarView.removeFromSuperview()
                reusableRadarCells.append(radarView)
            }
        }
    }
}


// MARK: 内部类

public extension RectRadarAnimationView {
    
    fileprivate class RadarCell: UIView {
        
        /// 进度 0.0...1.0
        var progress: CGFloat = 0 {
            didSet {
                setNeedsDisplay()
            }
        }
        
        /// 开始的矩形位置
        private var beginFrame: CGRect
        
        /// 最大扩展范围
        private var increment: CGFloat
        
        /// 填充色
        private var fillColor: UIColor
        
        /// 初始透明度
        private var beginAlpha: CGFloat
        
        init(beginFrame: CGRect, expand increment: CGFloat, fillColor: UIColor, beginAlpha: CGFloat) {
            self.beginFrame = beginFrame
            self.increment = increment
            self.fillColor = fillColor
            self.beginAlpha = beginAlpha
            super.init(frame: beginFrame.inset(by: UIEdgeInsets(-increment)))
            self.backgroundColor = .clear
        }
        
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        
        override func draw(_ rect: CGRect) {
            let currnetIncrement = increment * progress
            let drawRect = beginFrame.inset(by: UIEdgeInsets(-currnetIncrement))
            let path = UIBezierPath(roundedRect: drawRect, cornerRadius: min(drawRect.width, drawRect.height) * 0.5)
            
            path.fill(with: fillColor.withAlphaComponent((1 - progress) * beginAlpha))
        }
    }
}





/**
 * 用来不断添加cell的timer类, 设置每隔1秒添加一个cell
 */
fileprivate class RadarScheduler {
    
    static let manager = RadarScheduler()
    
    typealias Handle = () -> Void
    
    class Item {
        
        weak var target: NSObjectProtocol?
        var handle: Handle?
        
        init(target: NSObjectProtocol?, handle: Handle?) {
            self.target = target
            self.handle = handle
        }
    }
    
    init() {
        timer = Timer(fireAt: Date.distantFuture, interval: 1, target: self, selector: #selector(timerScheduled), userInfo: nil, repeats: true)
        RunLoop.current.add(timer, forMode: .common)
    }
    
    func remove(for identifier: AnyHashable) {
        values.removeValue(forKey: identifier)
        if values.count == 0 {
            timer.fireDate = Date.distantFuture
        }
    }
    
    // 添加target和selector, timer绑定的方法是timerScheduled, timerScheduled调用这个方法里面添加的信息
    func add(target: NSObjectProtocol, identifier: AnyHashable, _ handle: @escaping Handle) {
        values[identifier] = Item(target: target, handle: handle)
        if timer.isValid {
            timer.fireDate = Date()
        }
    }
    
    var values = [AnyHashable : Item]()
    var timer: Timer!
    
    @objc
    func timerScheduled() {
        values = values.filter { $0.value.target != nil }
        values.forEach { $0.value.handle?() }
    }
}


// MARK: AnimateScheduler:


/**
 * 用来不断给cell做动画的类, 每隔0.02秒执行一次
 */

fileprivate class AnimateScheduler {
    
    static let manager = AnimateScheduler()
    
    typealias Handle = () -> Void
    
    var values = [AnyHashable : Item]()
    
    var timer: Timer!
    
    class Item {
        
        weak var target: NSObjectProtocol?
        var handle: Handle?
        
        init(target: NSObjectProtocol?, handle: Handle?) {
            self.target = target
            self.handle = handle
        }
    }
    
    init() {
        timer = Timer(fireAt: Date.distantFuture, interval: 0.02, target: self, selector: #selector(timerScheduled), userInfo: nil, repeats: true)
        RunLoop.current.add(timer, forMode: .common)
    }
    
    func remove(for identifier: AnyHashable) {
        values.removeValue(forKey: identifier)
        if values.count == 0 {
            timer.fireDate = Date.distantFuture
        }
    }
    
    func add(target: NSObjectProtocol, identifier: AnyHashable, _ handle: @escaping Handle) {
        values[identifier] = Item(target: target, handle: handle)
        if timer.isValid {
            timer.fireDate = Date()
        }
    }
    
    @objc func timerScheduled() {
        values = values.filter { $0.value.target != nil }
        values.forEach { $0.value.handle?() }
    }
}
